<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.0.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">
  <link rel="alternate" href="/atom.xml" title="itheone" type="application/atom+xml">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css">


<script id="hexo-configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Gemini',
    version: '7.5.0',
    exturl: true,
    sidebar: {"position":"left","display":"post","offset":12,"onmobile":false},
    copycode: {"enable":true,"show_result":true,"style":"default"},
    back2top: {"enable":true,"sidebar":false,"scrollpercent":true},
    bookmark: {"enable":false,"color":"#222","save":"auto"},
    fancybox: false,
    mediumzoom: false,
    lazyload: false,
    pangu: false,
    algolia: {
      appID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    },
    localsearch: {"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},
    path: '',
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    sidebarPadding: 40
  };
</script>

  <meta name="description" content="[TOC]Java每日一题每日一题：什么是缓存穿透？如何解决？参考答案：缓存穿透是指用户查询数据，在数据库没有，自然在缓存中也不会有。这样就导致用户查询的时候，在缓存中找不到，每次都要去数据库再查询一遍，然后返回空（相当于进行了两次无用的查询）。这样请求就绕过缓存直接查数据库，这也是经常提的缓存命中率问题。解决办法;最常见的则是采用布隆过滤器，将所有可能存在的数据哈希到一个足够大的bitmap中，">
<meta property="og:type" content="article">
<meta property="og:title" content="java每日一题">
<meta property="og:url" content="https:&#x2F;&#x2F;www.caohaifeng.site&#x2F;2019&#x2F;12&#x2F;11&#x2F;Java%E6%AF%8F%E6%97%A5%E4%B8%80%E9%A2%98&#x2F;index.html">
<meta property="og:site_name" content="itheone">
<meta property="og:description" content="[TOC]Java每日一题每日一题：什么是缓存穿透？如何解决？参考答案：缓存穿透是指用户查询数据，在数据库没有，自然在缓存中也不会有。这样就导致用户查询的时候，在缓存中找不到，每次都要去数据库再查询一遍，然后返回空（相当于进行了两次无用的查询）。这样请求就绕过缓存直接查数据库，这也是经常提的缓存命中率问题。解决办法;最常见的则是采用布隆过滤器，将所有可能存在的数据哈希到一个足够大的bitmap中，">
<meta property="og:locale" content="zh-CN">
<meta property="og:updated_time" content="2019-11-28T09:47:29.126Z">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://www.caohaifeng.site/2019/12/11/Java%E6%AF%8F%E6%97%A5%E4%B8%80%E9%A2%98/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome: false,
    isPost: true,
    isPage: false,
    isArchive: false
  };
</script>

  <title>java每日一题 | itheone</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-meta">

    <div>
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">itheone</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
        <p class="site-subtitle">H</p>
  </div>

  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>
</div>


<nav class="site-nav">
  
  <ul id="menu" class="menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-fw fa-home"></i>首页</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="fa fa-fw fa-user"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-fw fa-tags"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-fw fa-th"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-fw fa-archive"></i>归档</a>

  </li>
        <li class="menu-item menu-item-schedule">

    <a href="/schedule/" rel="section"><i class="fa fa-fw fa-calendar"></i>日程表</a>

  </li>
        <li class="menu-item menu-item-commonweal">

    <a href="/404/" rel="section"><i class="fa fa-fw fa-heartbeat"></i>公益 404</a>

  </li>
  </ul>

</nav>
</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

  <span class="exturl github-corner" data-url="aHR0cHM6Ly9naXRodWIuY29tL2hldm9sZg==" title="Follow me on GitHub" aria-label="Follow me on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></span>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content">
            

  <div class="posts-expand">
      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block " lang="zh-CN">


  
  
  
    <div class="bottom-divider">
      <style>
        .bottom-divider {
          display: table;
          padding-bottom: 10px;
          margin-bottom: 50px;
          width: 100%;
          border-bottom: 1px solid #eee;
        }
      </style>
      <div class="post-nav-next post-nav-item">
        
          <a href="/2019/12/11/centos7%E5%AE%89%E8%A3%85jenkins/" rel="next" title="centos7安装jenkins">
            <i class="fa fa-chevron-left"></i> centos7安装jenkins
          </a>
        
      </div>

      <span class="post-nav-divider"></span>

      <div class="post-nav-prev post-nav-item">
        
          <a href="/2019/12/11/velocity/" rel="prev" title="velocity">
            velocity <i class="fa fa-chevron-right"></i>
          </a>
        
      </div>
    </div>
  

  
  
  
  
    
  
    <link itemprop="mainEntityOfPage" href="https://www.caohaifeng.site/2019/12/11/Java%E6%AF%8F%E6%97%A5%E4%B8%80%E9%A2%98/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.jpg">
      <meta itemprop="name" content="Haifeng Cao">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="itheone">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          java每日一题
        </h1>

        <div class="post-meta">

			
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2019-12-11 19:27:20" itemprop="dateCreated datePublished" datetime="2019-12-11T19:27:20+08:00">2019-12-11</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2019-11-28 17:47:29" itemprop="dateModified" datetime="2019-11-28T17:47:29+08:00">2019-11-28</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/java%E9%9D%A2%E8%AF%95%E9%A2%98/" itemprop="url" rel="index">
                    <span itemprop="name">java面试题</span>
                  </a>
                </span>
            </span>

          
            <span id="/2019/12/11/Java%E6%AF%8F%E6%97%A5%E4%B8%80%E9%A2%98/" class="post-meta-item leancloud_visitors" data-flag-title="java每日一题" title="阅读次数">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span class="leancloud-visitors-count"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="fa fa-comment-o"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/2019/12/11/Java%E6%AF%8F%E6%97%A5%E4%B8%80%E9%A2%98/#comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/2019/12/11/Java%E6%AF%8F%E6%97%A5%E4%B8%80%E9%A2%98/" itemprop="commentCount"></span>
    </a>
  </span>
  
  <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="fa fa-file-word-o"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>18k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="fa fa-clock-o"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>17 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <p>[TOC]</p><h1 id="Java每日一题"><a href="#Java每日一题" class="headerlink" title="Java每日一题"></a>Java每日一题</h1><h5 id="每日一题：什么是缓存穿透？如何解决？"><a href="#每日一题：什么是缓存穿透？如何解决？" class="headerlink" title="每日一题：什么是缓存穿透？如何解决？"></a>每日一题：什么是缓存穿透？如何解决？</h5><p>参考答案：缓存穿透是指用户查询数据，在数据库没有，自然在缓存中也不会有。这样就导致用户查询的时候，在缓存中找不到，每次都要去数据库再查询一遍，然后返回空（相当于进行了两次无用的查询）。这样请求就绕过缓存直接查数据库，这也是经常提的缓存命中率问题。<br>解决办法;<br>最常见的则是采用布隆过滤器，将所有可能存在的数据哈希到一个足够大的bitmap中，一个一定不存在的数据会被这个bitmap拦截掉，从而避免了对底层存储系统的查询压力。</p><a id="more"></a>

<h5 id="每日一小题，迈进BATJ-今天的题目是spring框架模块"><a href="#每日一小题，迈进BATJ-今天的题目是spring框架模块" class="headerlink" title="每日一小题，迈进BATJ:今天的题目是spring框架模块"></a>每日一小题，迈进BATJ:今天的题目是spring框架模块</h5><p>问题：</p>
<p>下面有关spring框架模块的描述，说法错误的是？<br>A.Spring Core：Core封装包是框架的最基础部分，提供IOC和依赖注入特性</p>
<p>B.AOP模块提供了AOP（拦截器）机制，并提供常用的拦截器，供用户自定义和配置</p>
<p>C.ORM模块提供了spring自己的实现，而且支持常用的Hibernate，ibtas，jdao等框架</p>
<p>D.DAO模块Spring 提供对JDBC的支持，对JDBC进行封装，允许JDBC使用Spring资源，并能统一管理JDBC事物，并不对JDBC进行实现</p>
<p>答案：C<br>解析：<br>七大模块，如下：</p>
<ol>
<li>Spring Core： Core封装包是框架的最基础部分，提供IOC和依赖注入特性。这里的基础概念是BeanFactory，它提供对Factory模式的经典实现来消除对程序性单例模式的需要，并真正地允许你从程序逻辑中分离出依赖关系和配置。</li>
</ol>
<p>2.Spring Context: 构建于Core封装包基础上的 Context封装包，提供了一种框架式的对象访问方法，有些象JNDI注册器。Context封装包的特性得自于Beans封装包，并添加了对国际化（I18N）的支持（例如资源绑定），事件传播，资源装载的方式和Context的透明创建，比如说通过Servlet容器。</p>
<p>3．Spring DAO:  DAO (Data Access Object)提供了JDBC的抽象层，它可消除冗长的JDBC编码和解析数据库厂商特有的错误代码。 并且，JDBC封装包还提供了一种比编程性更好的声明性事务管理方法，不仅仅是实现了特定接口，而且对所有的POJOs（plain old Java objects）都适用。</p>
<p>4.Spring ORM: ORM 封装包提供了常用的“对象/关系”映射APIs的集成层。 其中包括JPA、JDO、Hibernate 和 iBatis 。利用ORM封装包，可以混合使用所有Spring提供的特性进行“对象/关系”映射，如前边提到的简单声明性事务管理。</p>
<p>5.Spring AOP: Spring的 AOP 封装包提供了符合AOP Alliance规范的面向方面的编程实现，让你可以定义，例如方法拦截器（method-interceptors）和切点（pointcuts），从逻辑上讲，从而减弱代码的功能耦合，清晰的被分离开。而且，利用source-level的元数据功能，还可以将各种行为信息合并到你的代码中。</p>
<p>6.Spring Web: Spring中的 Web 包提供了基础的针对Web开发的集成特性，例如多方文件上传，利用Servlet listeners进行IOC容器初始化和针对Web的ApplicationContext。当与WebWork或Struts一起使用Spring时，这个包使Spring可与其他框架结合。</p>
<p>7.Spring Web MVC: Spring中的MVC封装包提供了Web应用的Model-View-Controller（MVC）实现。Spring的MVC框架并不是仅仅提供一种传统的实现，它提供了一种清晰的分离模型，在领域模型代码和Web Form之间。并且，还可以借助Spring框架的其他特性。</p>
<h5 id="每日一题：Redis单线程为什么这么快？"><a href="#每日一题：Redis单线程为什么这么快？" class="headerlink" title="每日一题：Redis单线程为什么这么快？"></a>每日一题：Redis单线程为什么这么快？</h5><p>参考答案：</p>
<p>(一)纯内存操作<br>(二)<strong>单线程</strong>操作，避免了频繁的上下文切换<br>(三)采用了非阻塞I/O多路复用机制<br>(四)RESP协议简单</p>
<h5 id="每日一题：SpringCloud断路器的作用"><a href="#每日一题：SpringCloud断路器的作用" class="headerlink" title="每日一题：SpringCloud断路器的作用"></a>每日一题：SpringCloud断路器的作用</h5><p>参考答案：当一个服务调用另一个服务由于网络原因或者自身原因出现问题时 ，调用者就会等待被调者的响应，<br>当更多的服务请求到这些资源时，导致更多的请求等待，这样就会发生连锁效应，断路器就是解决这一问题的。</p>
<p>断路器有完全打开状态：<br> 一定时间内，达到一定的次数无法调用，并且多次检测没有恢复的迹象，断路器完全打开，那么下次的请求不会请求到该服务。<br> 半开：<br>短时间内有回复迹象，断路器会将<strong>部分请求发送给服务</strong>，当能正常调用时，断路器关闭。<br> 关闭：<br>当服务一直处于正常状态，能正常调用，断路器关闭。</p>
<h5 id="每日一题：为什么要有TIME-WAIT状态？"><a href="#每日一题：为什么要有TIME-WAIT状态？" class="headerlink" title="每日一题：为什么要有TIME_WAIT状态？"></a>每日一题：为什么要有TIME_WAIT状态？</h5><p>TIME_WAIT状态存在有两个原因。<br>&lt;1&gt;可靠终止TCP连接。如果最后一个ACK报文因为网络原因被丢弃，此时server因为没有收到ACK而超时重传FIN报文，处于TIME_WAIT状态的client可以继续对FIN报文做回复，向server发送ACK报文。<br>&lt;2&gt;保证让迟来的TCP报文段有足够的时间被识别和丢弃。连接结束了，网络中的延迟报文也应该被丢弃掉，以免影响立刻建立的新连接。</p>
<h5 id="在-java-中守护线程和用户线程的区别？"><a href="#在-java-中守护线程和用户线程的区别？" class="headerlink" title="在 java 中守护线程和用户线程的区别？"></a>在 java 中守护线程和用户线程的区别？</h5><p>java 中的线程分为两种：守护线程（Daemon）和用户线程（User）。 </p>
<p>任何线程都可以设置为守护线程和用户线程，通过方法 </p>
<p>Thread.setDaemon(bool on)；true 则把该线程设置为守护线程，反之则为用户线 </p>
<p>程。Thread.setDaemon()必须在 Thread.start()之前调用，否则运行时会抛出异常。 </p>
<p>两者的区别： </p>
<p>唯一的区别是判断虚拟机(JVM)何时离开，Daemon 是为其他线程提供服务， </p>
<p>如果全部的 User Thread 已经结束，Daemon 没有可服务的线程，JVM 关闭。 </p>
<p>扩展：Thread Dump 打印出来的线程信息，含有 daemon 字样的线程即为守 </p>
<p>护进程</p>
<h5 id="线程与进程的区别"><a href="#线程与进程的区别" class="headerlink" title="线程与进程的区别"></a>线程与进程的区别</h5><p>进程是操作系统分配资源的最小单元，线程是操作系统调度的最小单元。 </p>
<p>一个程序至少有一个进程,一个进程至少有一个线程。 </p>
<h5 id="什么是多线程中的上下文切换"><a href="#什么是多线程中的上下文切换" class="headerlink" title="什么是多线程中的上下文切换"></a>什么是多线程中的上下文切换</h5><p>多线程会共同使用一组计算机上的 CPU，而线程数大于给程序分配的 CPU </p>
<p>数量时，为了让各个线程都有执行的机会，就需要轮转使用 CPU。不同的线程切 </p>
<p>换使用 CPU 发生的切换数据等就是上下文切换。 </p>
<h5 id="死锁与活锁的区别，死锁与饥饿的区别？"><a href="#死锁与活锁的区别，死锁与饥饿的区别？" class="headerlink" title="死锁与活锁的区别，死锁与饥饿的区别？"></a>死锁与活锁的区别，死锁与饥饿的区别？</h5><p>死锁：是指两个或两个以上的进程（或线程）在执行过程中，因争夺资源而 </p>
<p>造成的一种互相等待的现象，若无外力作用，它们都将无法推进下去。 </p>
<p>产生死锁的必要条件： </p>
<p>互斥条件：所谓互斥就是进程在某一时间内独占资源。 </p>
<p>请求与保持条件：一个进程因请求资源而阻塞时，对已获得的资源保持不放。 </p>
<p>不剥夺条件:进程已获得资源，在末使用完之前，不能强行剥夺。 </p>
<p>循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 </p>
<p>活锁：任务或者执行者没有被阻塞，由于某些条件没有满足，导致一直重复 </p>
<p>尝试，失败，尝试，失败。 </p>
<p>活锁和死锁的区别在于，处于活锁的实体是在不断的改变状态，所谓的“活”， </p>
<p>而处于死锁的实体表现为等待；活锁有可能自行解开，死锁则不能。 </p>
<p>饥饿：一个或者多个线程因为种种原因无法获得所需要的资源，导致一直无 </p>
<p>法执行的状态。 </p>
<h5 id="synchronized-底层实现原理"><a href="#synchronized-底层实现原理" class="headerlink" title="synchronized 底层实现原理"></a>synchronized 底层实现原理</h5><p>synchronized (this)原理：涉及两条指令：monitorenter，monitorexit；再说同 </p>
<p>步方法，从同步方法反编译的结果来看，方法的同步并没有通过指令 </p>
<p>monitorenter 和 monitorexit 来实现，相对于普通方法，其常量池中多了 </p>
<p>ACC_SYNCHRONIZED 标示符。JVM 就是根据该标示符来实现方法的同步的：当方法被调用时，调用指令将 </p>
<p>会==检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置，如果设置了，执行线== </p>
<p>==程将先获取 monitor，获取成功之后才能执行方法体，方法执行完后再释放== </p>
<p>==monitor==。在方法执行期间，其他任何线程都无法再获得同一个 monitor 对象。 </p>
<p>注意，这个问题可能会接着追问，java 对象头信息，偏向锁，轻量锁，重量 </p>
<p>级锁及其他们相互间转化。 </p>
<h5 id="什么是线程组，为什么在-Java-中不推荐使用？"><a href="#什么是线程组，为什么在-Java-中不推荐使用？" class="headerlink" title="什么是线程组，为什么在 Java 中不推荐使用？"></a>什么是线程组，为什么在 Java 中不推荐使用？</h5><p>ThreadGroup 类，可以把线程归属到某一个线程组中，线程组中可以有线程 </p>
<p>对象，也可以有线程组，组中还可以有线程，这样的组织结构有点类似于树的形 </p>
<p>式。</p>
<p>1.线程组 ThreadGroup 对象中比较有用的方法是 stop、resume、suspend 等 </p>
<p>方法，由于这几个方法会导致线程的安全问题（主要是死锁问题），已经被官方 </p>
<p>废弃掉了，所以线程组本身的应用价值就大打折扣了。 </p>
<p>2.线程组 ThreadGroup 不是线程安全的，这在使用过程中获取的信息并不全 </p>
<p>是及时有效的，这就降低了它的统计使用价值。 </p>
<h5 id="什么是-Executor-框架？为什么使用-Executor-框架？"><a href="#什么是-Executor-框架？为什么使用-Executor-框架？" class="headerlink" title="什么是 Executor 框架？为什么使用 Executor 框架？"></a>什么是 Executor 框架？为什么使用 Executor 框架？</h5><p>Executor 框架是一个根据一组执行策略调用，调度，执行和控制的异步任务 </p>
<p>的框架。</p>
<p>每次执行任务创建线程 new Thread()比较消耗性能，创建一个线程是比较耗 </p>
<p>时、耗资源的。 </p>
<p>调用 new Thread()创建的线程缺乏管理，而且可以无限制的创建，线程之间 </p>
<p>的相互竞争会导致过多占用系统资源而导致系统瘫痪，还有线程之间的频繁交替 </p>
<p>也会消耗很多系统资源。 </p>
<p>接使用 new Thread() 启动的线程不利于扩展，比如定时执行、定期执行、 </p>
<p>定时定期执行、线程中断等都不便实现。 </p>
<h5 id="在-Java-中-Executor-和-Executors-的区别？"><a href="#在-Java-中-Executor-和-Executors-的区别？" class="headerlink" title="在 Java 中 Executor 和 Executors 的区别？"></a>在 Java 中 Executor 和 Executors 的区别？</h5><p>Executors 工具类的不同方法按照我们的需求创建了不同的线程池，来满足 </p>
<p>业务的需求。 </p>
<p>Executor 接口对象能执行我们的线程任务。 </p>
<p>ExecutorService 接口继承了 Executor 接口并进行了扩展，提供了更多的方法 </p>
<p>我们能获得任务执行的状态并且可以获取任务的返回值。 </p>
<p>使用 ThreadPoolExecutor 可以创建自定义线程池。 </p>
<h5 id="什么是原子操作？在-Java-Concurrency-API-中有哪些原子类-atomicclasses-？"><a href="#什么是原子操作？在-Java-Concurrency-API-中有哪些原子类-atomicclasses-？" class="headerlink" title="什么是原子操作？在 Java Concurrency API 中有哪些原子类(atomicclasses)？"></a>什么是原子操作？在 Java Concurrency API 中有哪些原子类(atomicclasses)？</h5><p>原子操作（atomic operation）意为”不可被中断的一个或一系列操作” 。 </p>
<p>处理器使用基于对缓存加锁或总线加锁的方式来实现多处理器之间的原子 </p>
<p>操作。在 Java 中可以通过锁和循环 CAS 的方式来实现原子操作。 CAS 操作—— </p>
<p>Compare &amp; Set，或是 Compare &amp; Swap，现在几乎所有的 CPU 指令都支持 CAS 的 </p>
<p>原子操作。java.util.concurrent.atomic 下提供了大量的原子操作类，比如原子类： </p>
<p>AtomicBoolean，AtomicInteger，AtomicLong，AtomicReference ，原子数组： </p>
<p>AtomicIntegerArray，AtomicLongArray，AtomicReferenceArray ，原子属性更新器： </p>
<p>AtomicLongFieldUpdater，AtomicIntegerFieldUpdater，AtomicReferenceFieldUpdater </p>
<h5 id="Java-Concurrency-API-中的-Lock-接口-Lock-interface-是什么？对比synchronized-它有什么优势？"><a href="#Java-Concurrency-API-中的-Lock-接口-Lock-interface-是什么？对比synchronized-它有什么优势？" class="headerlink" title="Java Concurrency API 中的 Lock 接口(Lock interface)是什么？对比synchronized 它有什么优势？"></a>Java Concurrency API 中的 Lock 接口(Lock interface)是什么？对比synchronized 它有什么优势？</h5><p>Lock 接口比同步方法和同步块提供了更具扩展性的锁操作。 </p>
<p>他们允许更灵活的结构，可以具有完全不同的性质，并且可以支持多个相关 </p>
<p>类的条件对象。 </p>
<p>它的优势有：可以使锁更公平，可以使线程在等待锁的时候响应中断，可以 </p>
<p>让线程尝试获取锁，并在无法获取锁的时候立即返回或者等待一段时间，可以在 </p>
<p>不同的范围，以不同的顺序获取和释放锁。 </p>
<p>整体上来说 Lock 是 synchronized 的扩展版，Lock 提供了无条件的、可轮询 </p>
<p>的(tryLock 方法)、定时的(tryLock 带参方法)、可中断的(lockInterruptibly)、可多条 </p>
<p>件队列的(newCondition 方法)锁操作。另外 Lock 的实现类基本都支持非公平锁(默 </p>
<p>认)和公平锁，synchronized 只支持非公平锁，当然，在大部分情况下，非公平锁 </p>
<p>是高效的选择。 </p>
<h5 id="什么是阻塞队列？阻塞队列的实现原理是什么？如何使用阻塞队列来实现生产者-消费者模型？"><a href="#什么是阻塞队列？阻塞队列的实现原理是什么？如何使用阻塞队列来实现生产者-消费者模型？" class="headerlink" title="什么是阻塞队列？阻塞队列的实现原理是什么？如何使用阻塞队列来实现生产者-消费者模型？"></a>什么是阻塞队列？阻塞队列的实现原理是什么？如何使用阻塞队列来实现生产者-消费者模型？</h5><p>阻塞队列（BlockingQueue）是一个支持两个附加操作的队列。 </p>
<p>这两个附加的操作是：在队列为空时，获取元素的线程会等待队列变为非空。 </p>
<p>当队列满时，存储元素的线程会等待队列可用。 </p>
<p>阻塞队列常用于生产者和消费者的场景，生产者是往队列里添加元素的线程， </p>
<p>消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器，而消费 </p>
<p>者也只从容器里拿元素。 </p>
<p>JDK7 提供了 7 个阻塞队列。==在实现上，主要是利用了 Condition 和 Lock 的等== </p>
<p>==待通知模式==。 </p>
<h5 id="什么是-Callable-和-Future"><a href="#什么是-Callable-和-Future" class="headerlink" title="什么是 Callable 和 Future?"></a>什么是 Callable 和 Future?</h5><p>Callable 接口类似于 Runnable，从名字就可以看出来了，但是 Runnable 不会 </p>
<p>返回结果，并且无法抛出返回结果的异常，而 Callable 功能更强大一些，被线程 </p>
<p>执行后，可以返回值，这个返回值可以被 Future 拿到，也就是说，Future 可以 </p>
<p>拿到异步执行任务的返回值。 </p>
<p>可以认为是带有回调的 Runnable。 </p>
<p>Future 接口表示异步任务，是还没有完成的任务给出的未来结果。所以说 </p>
<p>Callable 用于产生结果，Future 用于获取结果。 </p>
<h5 id="什么是-FutureTask"><a href="#什么是-FutureTask" class="headerlink" title="什么是 FutureTask?"></a>什么是 FutureTask?</h5><p>在 Java 并发程序中 FutureTask 表示一个可以取消的异步运算。它有启动和 </p>
<p>取消运算、查询运算是否完成和取回运算结果等方法。只有当运算完成的时候结果才能取回，如果运算尚未完成 get 方法将会阻塞。一个 FutureTask 对象可以对 </p>
<p>调用了 Callable 和 Runnable 的对象进行包装，由于 FutureTask 也是调用了 </p>
<p>Runnable 接口所以它可以提交给 Executor 来执行。 </p>
<h5 id="什么是并发容器的实现？"><a href="#什么是并发容器的实现？" class="headerlink" title="什么是并发容器的实现？"></a>什么是并发容器的实现？</h5><p>何为同步容器：可以简单地理解为通过 synchronized 来实现同步的容器，如 </p>
<p>果有多个线程调用同步容器的方法，它们将会串行执行。比如 ==Vector，Hashtable，== </p>
<p>==以及 Collections.synchronizedSet，synchronizedList== 等方法返回的容器。 </p>
<p>并发容器使用了与同步容器完全不同的加锁策略来提供更高的并发性和伸 </p>
<p>缩性，==例如在 ConcurrentHashMap 中采用了一种粒度更细的加锁机制，可以称为== </p>
<p>==分段锁==，在这种锁机制下，允许任意数量的读线程并发地访问 map，并且执行读 </p>
<p>操作的线程和写操作的线程也可以并发的访问 map，同时允许一定数量的写操作 </p>
<p>线程并发地修改 map，所以它可以在并发环境下实现更高的吞吐量。 </p>
<h5 id="多线程同步和互斥有几种实现方法，都是什么？"><a href="#多线程同步和互斥有几种实现方法，都是什么？" class="headerlink" title="多线程同步和互斥有几种实现方法，都是什么？"></a>多线程同步和互斥有几种实现方法，都是什么？</h5><p>线程同步是指线程之间所具有的一种制约关系，一个线程的执行依赖另一个 </p>
<p>线程的消息，当它没有得到另一个线程的消息时应等待，直到消息到达时才被唤 </p>
<p>醒。</p>
<p>线程互斥是指对于共享的进程系统资源，在各单个线程访问时的排它性。当 </p>
<p>有若干个线程都要使用某一共享资源时，任何时刻最多只允许一个线程去使用， </p>
<p>其它要使用该资源的线程必须等待，直到占用资源者释放该资源。线程互斥可以 </p>
<p>看成是一种特殊的线程同步。 </p>
<p>==线程间的同步方法大体可分为两类：用户模式和内核模式==。顾名思义，内核 </p>
<p>模式就是指利用系统内核对象的单一性来进行同步，使用时需要切换内核态与用 </p>
<p>户态，而用户模式就是不需要切换到内核态，只在用户态完成操作。 </p>
<p>用户模式下的方法有：原子操作（例如一个单一的全局变量），临界区。内 </p>
<p>核模式下的方法有：事件，信号量，互斥量。 </p>
<h5 id="为什么我们调用-start-方法时会执行-run-方法，为什么我们不能直接调用-run-方法"><a href="#为什么我们调用-start-方法时会执行-run-方法，为什么我们不能直接调用-run-方法" class="headerlink" title="为什么我们调用 start()方法时会执行 run()方法，为什么我们不能直接调用 run()方法?"></a>为什么我们调用 start()方法时会执行 run()方法，为什么我们不能直接调用 run()方法?</h5><p>当你调用 start()方法时你将创建新的线程，并且执行在 run()方法里的代码。 </p>
<p>但是如果你直接调用 run()方法，它不会创建新的线程也不会执行调用线程 </p>
<p>的代码，只会把 run 方法当作普通方法去执行。 </p>
<h5 id="在-Java-中-CycliBarriar-和-CountdownLatch-有什么区别？"><a href="#在-Java-中-CycliBarriar-和-CountdownLatch-有什么区别？" class="headerlink" title="在 Java 中 CycliBarriar 和 CountdownLatch 有什么区别？"></a>在 Java 中 CycliBarriar 和 CountdownLatch 有什么区别？</h5><p>CyclicBarrier 可以重复使用，而 CountdownLatch 不能重复使用。 </p>
<h5 id="什么是不可变对象，它对写并发应用有什么帮助？"><a href="#什么是不可变对象，它对写并发应用有什么帮助？" class="headerlink" title="什么是不可变对象，它对写并发应用有什么帮助？"></a>什么是不可变对象，它对写并发应用有什么帮助？</h5><p>不可变对象(Immutable Objects)即对象一旦被创建它的状态（对象的数据， </p>
<p>也即对象属性值）就不能改变，反之即为可变对象(Mutable Objects)。 </p>
<p>不可变对象的类即为不可变类(Immutable Class)。Java 平台类库中包含许多 </p>
<p>不可变类，如 String、基本类型的包装类、BigInteger 和 BigDecimal 等。不可变对象天生是线程安全的。它们的常量（域）是在构造函数中创建的。 </p>
<p>既然它们的状态无法修改，这些常量永远不会变。 </p>
<p>不可变对象永远是线程安全的。 </p>
<p>只有满足如下状态，一个对象才是不可变的； </p>
<p>它的状态不能在创建后再被修改； </p>
<p>所有域都是 final 类型；并且， </p>
<p>它被正确创建 </p>
<h5 id="notify-和-notifyAll-有什么区别？"><a href="#notify-和-notifyAll-有什么区别？" class="headerlink" title="notify()和 notifyAll()有什么区别？"></a>notify()和 notifyAll()有什么区别？</h5><p>当一个线程进入 wait 之后，就必须等其他线程 notify/notifyall,使用 notifyall, </p>
<p>可以唤醒所有处于 wait 状态的线程，使其重新进入锁的争夺队列中，而 notify </p>
<p>只能唤醒一个。 </p>
<p>如果没把握，建议 notifyAll，防止 notigy 因为信号丢失而造成程序异常。 </p>
<h5 id="什么是可重入锁（ReentrantLock）？谈谈它的实现。"><a href="#什么是可重入锁（ReentrantLock）？谈谈它的实现。" class="headerlink" title="什么是可重入锁（ReentrantLock）？谈谈它的实现。"></a>什么是可重入锁（ReentrantLock）？谈谈它的实现。</h5><p>线程可以重复进入任何一个它已经拥有的锁所同步着的代码块， </p>
<p>synchronized、ReentrantLock 都是可重入的锁。在实现上，就是线程每次获取锁 </p>
<p>时判定如果获得锁的线程是它自己时，简单将计数器累积即可，每 释放一次锁， </p>
<p>进行计数器累减，直到计算器归零，表示线程已经彻底释放锁。 </p>
<h5 id="当一个线程进入某个对象的一个-synchronized-的实例方法后，其它线程是否可进入此对象的其它方法？"><a href="#当一个线程进入某个对象的一个-synchronized-的实例方法后，其它线程是否可进入此对象的其它方法？" class="headerlink" title="当一个线程进入某个对象的一个 synchronized 的实例方法后，其它线程是否可进入此对象的其它方法？"></a>当一个线程进入某个对象的一个 synchronized 的实例方法后，其它线程是否可进入此对象的其它方法？</h5><p>如果其他方法没有 synchronized 的话，其他线程是可以进入的。 </p>
<p>所以要开放一个线程安全的对象时，得保证每个方法都是线程安全的。 </p>
<h5 id="乐观锁和悲观锁的理解及如何实现，有哪些实现方式？"><a href="#乐观锁和悲观锁的理解及如何实现，有哪些实现方式？" class="headerlink" title="乐观锁和悲观锁的理解及如何实现，有哪些实现方式？"></a>乐观锁和悲观锁的理解及如何实现，有哪些实现方式？</h5><p><strong>悲观锁：</strong>总是假设最坏的情况，每次去拿数据的时候都认为别人会修改，所 </p>
<p>以每次在拿数据的时候都会上锁，这样别人想拿这个数据就会阻塞直到它拿到锁。 </p>
<p>Java 里面的同步原语 synchronized 关键字的实现是悲观锁。 </p>
<p><strong>乐观锁：</strong>顾名思义，就是很乐观，每次去拿数据的时候都认为别人不会修改， </p>
<p>所以不会上锁，但是在更新的时候会判断一下在此期间别人有没有去更新这个数 </p>
<p>据，可以使用版本号等机制。在 Java 中 j 原子变量类就是使用了乐观锁的一种实 </p>
<p>现方式 CAS 实现的。 </p>
<p>乐观锁的实现方式： </p>
<p> 使用版本标识来确定读到的数据与提交时的数据是否一致。提交 </p>
<p>后修改版本标识，不一致时可以采取丢弃和再次尝试的策略。 </p>
<p> java 中的 Compare and Swap 即 CAS ，当多个线程尝试使用 CAS </p>
<p>同时更新同一个变量时，只有其中一个线程能更新变量的值，而其它线程 </p>
<p>都失败，失败的线程并不会被挂起，而是被告知这次竞争中失败，并可以 </p>
<p>再次尝试。 </p>
<h5 id="什么是-CAS-操作，缺点是什么？"><a href="#什么是-CAS-操作，缺点是什么？" class="headerlink" title="什么是 CAS 操作，缺点是什么？"></a>什么是 CAS 操作，缺点是什么？</h5><p>CAS 的基本思路就是，如果这个地址上的值和期望的值相等，则给其赋予新 </p>
<p>值，否则不做任何事儿，但是要返回原值是多少。每一个 CAS 操作过程都包含三个运算符：一个内存地址 V，一个期望的值 A 和一个新值 B，操作的时候如果这 </p>
<p>个地址上存放的值等于这个期望的值 A，则将地址上的值赋为新值 B，否则不做 </p>
<p>任何操作。 </p>
<p>CAS 缺点： </p>
<ul>
<li>ABA 问题： </li>
</ul>
<p>比如说一个线程 one 从内存位置 V 中取出 A，这时候另一个线程 two 也从内 </p>
<p>存中取出 A，并且 two 进行了一些操作变成了 B，然后 two 又将 V 位置的数据变 </p>
<p>成 A，这时候线程 one 进行 CAS 操作发现内存中仍然是 A，然后 one 操作成功。 </p>
<p>尽管线程 one 的 CAS 操作成功，但可能存在潜藏的问题。从 Java1.5 开始 JDK 的 </p>
<p>atomic 包里提供了一个类 AtomicStampedReference 来解决 ABA 问题。 </p>
<ul>
<li>循环时间长开销大： </li>
</ul>
<p>对于资源竞争严重（线程冲突严重）的情况，CAS 自旋的概率会比较大，从 </p>
<p>而浪费更多的 CPU 资源，效率低于 synchronized。 </p>
<p>只能保证一个共享变量的原子操作： </p>
<p>当对一个共享变量执行操作时，我们可以使用循环 CAS 的方式来保证原子操 </p>
<p>作，但是对多个共享变量操作时，循环 CAS 就无法保证操作的原子性，这个时候 </p>
<p>就可以用锁。 </p>
<h5 id="SynchronizedMap-和-ConcurrentHashMap-有什么区别？"><a href="#SynchronizedMap-和-ConcurrentHashMap-有什么区别？" class="headerlink" title="SynchronizedMap 和 ConcurrentHashMap 有什么区别？"></a>SynchronizedMap 和 ConcurrentHashMap 有什么区别？</h5><p>SynchronizedMap 一次锁住整张表来保证线程安全，所以每次只能有一个线 </p>
<p>程来访为 map。 </p>
<p>ConcurrentHashMap 使用分段锁来保证在多线程下的性能。 </p>
<h5 id="写时复制容器可以用于什么应用场景？"><a href="#写时复制容器可以用于什么应用场景？" class="headerlink" title="写时复制容器可以用于什么应用场景？"></a>写时复制容器可以用于什么应用场景？</h5><p>CopyOnWrite 并发容器用于对于绝大部分访问都是读，且<strong>只是偶尔写</strong>的并发 </p>
<p>场景。比如白名单，黑名单，商品类目的访问和更新场景。 </p>
<p>透露的思想 </p>
<p>读写分离，读和写分开 </p>
<p>最终一致性 </p>
<p>使用另外开辟空间的思路，来解决并发冲突 </p>
<h5 id="volatile-有什么用？能否用一句话说明下-volatile-的应用场景？"><a href="#volatile-有什么用？能否用一句话说明下-volatile-的应用场景？" class="headerlink" title="volatile 有什么用？能否用一句话说明下 volatile 的应用场景？"></a>volatile 有什么用？能否用一句话说明下 volatile 的应用场景？</h5><p>volatile 保证内存可见性和禁止指令重排。 </p>
<p>volatile 用于多线程环境下的一写多读，或者无关联的多写。 </p>
<p><strong>为什么代码会重排序？</strong> </p>
<p>在执行程序时，为了提供性能，处理器和编译器常常会对指令进行重排序， </p>
<p>但是不能随意重排序，不是你想怎么排序就怎么排序，它需要满足以下两个条件： </p>
<p>在单线程环境下不能改变程序运行的结果； </p>
<p>存在数据依赖关系的不允许重排序 </p>
<h5 id="在-java-中-wait-和-sleep-方法的不同？"><a href="#在-java-中-wait-和-sleep-方法的不同？" class="headerlink" title="在 java 中 wait 和 sleep 方法的不同？"></a>在 java 中 wait 和 sleep 方法的不同？</h5><p>最大的不同是在等待时 wait 会释放锁，而 sleep 一直持有锁。Wait 通常被用 </p>
<p>于线程间交互，sleep 通常被用于暂停执行。 </p>
<h5 id="一个线程运行时发生异常会怎样？"><a href="#一个线程运行时发生异常会怎样？" class="headerlink" title="一个线程运行时发生异常会怎样？"></a>一个线程运行时发生异常会怎样？</h5><p>如果异常没有被捕获该线程将会停止执行。hread.UncaughtExceptionHandler </p>
<p>是用于处理未捕获异常造成线程突然中断情况的一个内嵌接口。当一个未捕获异 </p>
<p>常将造成线程中断的时候 JVM 会使用 Thread.getUncaughtExceptionHandler()来查 </p>
<p>询线程的 UncaughtExceptionHandler 并将线程和异常作为参数传递给 handler 的 </p>
<p>uncaughtException()方法进行处理。 </p>
<p><strong>为什么 wait, notify 和 notifyAll 这些方法不在 thread 类里面？</strong> </p>
<p>JAVA 提供的锁是对象级的而不是线程级的，每个对象都有锁，通过线程获 </p>
<p>得。如果线程需要等待某些锁那么调用对象中的 wait()方法就有意义了。如果 </p>
<p>wait()方法定义在 Thread 类中，线程正在等待的是哪个锁就不明显了。简单的说， </p>
<p>由于 wait，notify 和 notifyAll 都是锁级别的操作，所以把他们定义在 Object 类中 </p>
<p>因为锁属于对象。 </p>
<h5 id="什么是-ThreadLocal-变量？"><a href="#什么是-ThreadLocal-变量？" class="headerlink" title="什么是 ThreadLocal 变量？"></a>什么是 ThreadLocal 变量？</h5><p>ThreadLocal 是 Java 里一种特殊的变量。每个线程都有一个 ThreadLocal 就是 </p>
<p>每个线程都拥有了自己独立的一个变量，竞争条件被彻底消除了。 </p>
<h5 id="Java-中-interrupted-和-isInterrupted-方法的区别？"><a href="#Java-中-interrupted-和-isInterrupted-方法的区别？" class="headerlink" title="Java 中 interrupted 和 isInterrupted 方法的区别？"></a>Java 中 interrupted 和 isInterrupted 方法的区别？</h5><p>interrupted() 和 isInterrupted()的主要区别是前者会将中断状态清除而后者 </p>
<p>不会。Java 多线程的中断机制是用内部标识来实现的，调用 Thread.interrupt()来 </p>
<p>中断一个线程就会设置中断标识为 true。当中断线程调用静态方法 </p>
<p>Thread.interrupted()来检查中断状态时，中断状态会被清零。而非静态方法 </p>
<p>isInterrupted()用来查询其它线程的中断状态且不会改变中断状态标识。 </p>
<h5 id="为什么-wait-和-notify-方法要在同步块中调用？"><a href="#为什么-wait-和-notify-方法要在同步块中调用？" class="headerlink" title="为什么 wait 和 notify 方法要在同步块中调用？"></a>为什么 wait 和 notify 方法要在同步块中调用？</h5><p>主要是因为 Java API 强制要求这样做，如果你不这么做，你的代码会抛出 </p>
<p><code>IllegalMonitorStateException</code> 异常。 </p>
<h5 id="为什么你应该在循环中检查等待条件"><a href="#为什么你应该在循环中检查等待条件" class="headerlink" title="为什么你应该在循环中检查等待条件?"></a>为什么你应该在循环中检查等待条件?</h5><p>处于等待状态的线程==可能会收到错误警报和伪唤醒==，如果不在循环中检查等 </p>
<p>待条件，程序就会在没有满足结束条件的情况下退出。因此，当一个等待线程醒 </p>
<p>来时，不能认为它原来的等待状态仍然是有效的，在 notify()方法调用之后和等 </p>
<p>待线程醒来之前这段时间它可能会改变。这就是在循环中使用 wait()方法效果更 </p>
<p>好的原因==(再次唤醒时，相关数据可能已经改变，需再次检查)==</p>
<h5 id="怎么检测一个线程是否拥有锁？"><a href="#怎么检测一个线程是否拥有锁？" class="headerlink" title="怎么检测一个线程是否拥有锁？"></a>怎么检测一个线程是否拥有锁？</h5><p>在 java.lang.Thread 中有一个方法叫 holdsLock()，它返回 true 如果当且仅当 </p>
<p>当前线程拥有某个具体对象的锁。 </p>
<h5 id="你如何在-Java-中获取线程堆栈？"><a href="#你如何在-Java-中获取线程堆栈？" class="headerlink" title="你如何在 Java 中获取线程堆栈？"></a>你如何在 Java 中获取线程堆栈？</h5><p><code>kill -3 [java pid]</code> </p>
<p>不会在当前终端输出，它会输出到代码执行的或指定的地方去。比如，kill -3 </p>
<p>tomcat pid, 输出堆栈到 log 目录下。 </p>
<p><code>Jstack [java pid]</code>这个比较简单，在当前终端显示，也可以重定向到指定文件中。 </p>
<p>或者使用 Java 提供的拟机线程系统的管理接口 </p>
<p>ManagementFactory.getThreadMXBean()。 </p>
<h5 id="Java-线程池中-submit-和-execute-方法有什么区别？"><a href="#Java-线程池中-submit-和-execute-方法有什么区别？" class="headerlink" title="Java 线程池中 submit() 和 execute()方法有什么区别？"></a>Java 线程池中 submit() 和 execute()方法有什么区别？</h5><p>两个方法都可以向线程池提交任务，execute()方法的返回类型是 void，它定 </p>
<p>义在 Executor 接口中。 </p>
<p>而 submit()方法可以==返回持有计算结果==的 Future 对象，它定义在 </p>
<p>ExecutorService 接口中，它扩展了 Executor 接口 </p>
<h5 id="你对线程优先级的理解是什么？"><a href="#你对线程优先级的理解是什么？" class="headerlink" title="你对线程优先级的理解是什么？"></a>你对线程优先级的理解是什么？</h5><p>每一个线程都是有优先级的，一般来说，高优先级的线程在运行时会具有优 </p>
<p>先权，但这==依赖于线程调度的实现==，这个实现是和操作系统相关的(OS dependent)。 </p>
<p>我们可以定义线程的优先级，但是这并不能保证高优先级的线程会在低优先级的 </p>
<p>线程前执行。线程优先级是一个 int 变量(从 1-10)，1 代表最低优先级，10 代表 </p>
<p>最高优先级。 </p>
<p>java 的线程优先级调度会委托给操作系统去处理，所以与具体的操作系统优 </p>
<p>先级有关，如非特别需要，一般无需设置线程优先级。 </p>
<h5 id="你如何确保-main-方法所在的线程是-Java-程序最后结束的线程"><a href="#你如何确保-main-方法所在的线程是-Java-程序最后结束的线程" class="headerlink" title="你如何确保 main()方法所在的线程是 Java 程序最后结束的线程"></a>你如何确保 main()方法所在的线程是 Java 程序最后结束的线程</h5><p>可以使用 Thread 类的 join()方法（或者 CountDownLatch 工具类）来确保所 </p>
<p>有程序创建的线程在 main()方法退出前结束。 </p>
<h5 id="为什么-Thread-类的-sleep-和-yield-方法是静态的？"><a href="#为什么-Thread-类的-sleep-和-yield-方法是静态的？" class="headerlink" title="为什么 Thread 类的 sleep()和 yield ()方法是静态的？"></a>为什么 Thread 类的 sleep()和 yield ()方法是静态的？</h5><p>Thread 类的 sleep()和 yield()方法将在==当前正在执行的线程上==运行。所以在其 </p>
<p>他处于等待状态的线程上调用这些方法是没有意义的。这就是为什么这些方法是 </p>
<p>静态的。它们可以在当前正在执行的线程中工作，并避免程序员错误的认为可以 </p>
<p>在其他非运行线程调用这些方法。 </p>
<h5 id="现在有-T1、T2、T3-三个线程，你怎样保证-T2-在-T1-执行完后执行，T3-在-T2-执行完后执行？"><a href="#现在有-T1、T2、T3-三个线程，你怎样保证-T2-在-T1-执行完后执行，T3-在-T2-执行完后执行？" class="headerlink" title="现在有 T1、T2、T3 三个线程，你怎样保证 T2 在 T1 执行完后执行，T3 在 T2 执行完后执行？"></a>现在有 T1、T2、T3 三个线程，你怎样保证 T2 在 T1 执行完后执行，T3 在 T2 执行完后执行？</h5><p>可以用 join 方法实现。 </p>
<h5 id="你需要实现一个高效的缓存，它允许多个用户读，但只允许一个用户写，以此来保持它的完整性，你会怎样去实现它？"><a href="#你需要实现一个高效的缓存，它允许多个用户读，但只允许一个用户写，以此来保持它的完整性，你会怎样去实现它？" class="headerlink" title="你需要实现一个高效的缓存，它允许多个用户读，但只允许一个用户写，以此来保持它的完整性，你会怎样去实现它？"></a>你需要实现一个高效的缓存，它允许多个用户读，但只允许一个用户写，以此来保持它的完整性，你会怎样去实现它？</h5><p>==volatile 关键字，读写锁，写时复制等等都可以实现。== </p>
<p><strong>用 Java 实现阻塞队列</strong> </p>
<p>见作业答案：包 cn.enjoyedu.ch5.answer 下 </p>
<p><strong>用 Java 写代码来解决生产者——消费者问题。</strong> </p>
<p>==阻塞队列==实现即可，也可以用 wait 和 notify 来解决这个问题，或者用 </p>
<p>Semaphore </p>
<h5 id="用-Java-编程一个会导致死锁的程序，你将怎么解决？"><a href="#用-Java-编程一个会导致死锁的程序，你将怎么解决？" class="headerlink" title="用 Java 编程一个会导致死锁的程序，你将怎么解决？"></a>用 Java 编程一个会导致死锁的程序，你将怎么解决？</h5><p>参见代码 cn.enjoyedu.ch7. NormalDeadLock，如何解决死锁，参见笔记。 </p>
<h5 id="Java-中如何停止一个线程？"><a href="#Java-中如何停止一个线程？" class="headerlink" title="Java 中如何停止一个线程？"></a>Java 中如何停止一个线程？</h5><ul>
<li>使用共享变量的方式 </li>
</ul>
<p>在这种方式中，之所以引入共享变量，是因为该变量可以被多个执行相同任 </p>
<p>务的线程用来作为是否中断的信号，通知中断线程的执行。 </p>
<ul>
<li>使用 interrupt 方法终止线程 </li>
</ul>
<p>如果一个线程由于等待某些事件的发生而被阻塞，又该怎样停止该线程呢？ </p>
<p>比如当一个线程由于需要等候键盘输入而被阻塞，或者调用 Thread.join()方法， </p>
<p>或者 Thread.sleep()方法，在网络中调用 ServerSocket.accept()方法，或者调用了 </p>
<p>DatagramSocket.receive()方法时，都有可能导致线程阻塞，使线程处于处于不可 </p>
<p>运行状态时，即使主程序中将该线程的共享变量设置为 true，但该线程此时根本 </p>
<p>无法检查循环标志，当然也就无法立即中断。所以应该尽量使用 Thread 提供的 </p>
<p>interrupt()方法，因为该方法虽然不会中断一个正在运行的线程，但是它可以使 </p>
<p>一个被阻塞的线程抛出一个中断异常，从而使线程提前结束阻塞状态。 </p>
<h5 id="JVM-中哪个参数是用来控制线程的栈堆栈大小的"><a href="#JVM-中哪个参数是用来控制线程的栈堆栈大小的" class="headerlink" title="JVM 中哪个参数是用来控制线程的栈堆栈大小的"></a>JVM 中哪个参数是用来控制线程的栈堆栈大小的</h5><p>-Xss </p>
<h5 id="如果同步块内的线程抛出异常锁会释放吗？"><a href="#如果同步块内的线程抛出异常锁会释放吗？" class="headerlink" title="如果同步块内的线程抛出异常锁会释放吗？"></a>如果同步块内的线程抛出异常锁会释放吗？</h5><p>会</p>
<h5 id="单例模式的双重检查实现是什么？为什么并不安全？如何在-Java-中创建线程安全的-Singleton？"><a href="#单例模式的双重检查实现是什么？为什么并不安全？如何在-Java-中创建线程安全的-Singleton？" class="headerlink" title="单例模式的双重检查实现是什么？为什么并不安全？如何在 Java 中创建线程安全的 Singleton？"></a>单例模式的双重检查实现是什么？为什么并不安全？如何在 Java 中创建线程安全的 Singleton？</h5><p>实现参见 cn.enjoyedu.ch7.dcl. SingleDcl，不安全的根本原因是重排序会导致 </p>
<p>未初始化完成的对象可以被其他线程看见而导致错误。创建安全的单例模式有： </p>
<p>延迟占位模式、在声明的时候就 new 这个类的实例、枚举 </p>
<h5 id="写出-3-条你遵循的多线程最佳实践"><a href="#写出-3-条你遵循的多线程最佳实践" class="headerlink" title="写出 3 条你遵循的多线程最佳实践"></a>写出 3 条你遵循的多线程最佳实践</h5><p>给你的线程起个有意义的名字。 这样可以方便找 bug 或追踪。 </p>
<p>OrderProcessor, QuoteProcessor or TradeProcessor 这种名字比 Thread-1. </p>
<p>Thread-2 and Thread-3 好多了，给线程起一个和它要完成的任务相关的名字，所 </p>
<p>有的主要框架甚至 JDK 都遵循这个最佳实践。 </p>
<p>避免锁定和缩小同步的范围 锁花费的代价高昂且上下文切换更耗费时间空 </p>
<p>间，试试最低限度的使用同步和锁，缩小临界区。因此相对于同步方法我更喜欢 </p>
<p>同步块，它给我拥有对锁的绝对控制权。 </p>
<p>多用同步类少用 wait 和 notify 首先，CountDownLatch, Semaphore, </p>
<p>CyclicBarrier 和 Exchanger 这些同步类简化了编码操作，而用 wait 和 notify 很难 </p>
<p>实现对复杂控制流的控制。其次，这些类是由最好的企业编写和维护在后续的JDK </p>
<p>中它们还会不断优化和完善，使用这些更高等级的同步工具你的程序可以不费吹 </p>
<p>灰之力获得优化。 </p>
<p>多用并发集合少用同步集合 这是另外一个容易遵循且受益巨大的最佳实践， </p>
<p>并发集合比同步集合的可扩展性更好，所以在并发编程时使用并发集合效果更好。 </p>
<p>比如并发编程的黄金原则，尽量无锁化编程等等…….. </p>
<h5 id="请概述线程池的创建参数，怎么样合理配置一个线程池的参数？"><a href="#请概述线程池的创建参数，怎么样合理配置一个线程池的参数？" class="headerlink" title="请概述线程池的创建参数，怎么样合理配置一个线程池的参数？"></a>请概述线程池的创建参数，怎么样合理配置一个线程池的参数？</h5><p>参见笔记中线程池一章的内容 </p>
<h5 id="请概述锁的公平和非公平，JDK-内部是如何实现的。"><a href="#请概述锁的公平和非公平，JDK-内部是如何实现的。" class="headerlink" title="请概述锁的公平和非公平，JDK 内部是如何实现的。"></a>请概述锁的公平和非公平，JDK 内部是如何实现的。</h5><p>公平锁是指所有试图获得锁的线程按照获取锁的顺序依次获得锁，而非公平 </p>
<p>锁则是当前的锁状态没有被占用时,当前线程可以直接占用,而不需要等待。在实 </p>
<p>现上，非公平锁逻辑基本跟公平锁一致，唯一的区别是，当前线程不需要判断==同== </p>
<p>==步队列中是否有等待线程==。 </p>
<p>非公平锁性能高于公平锁性能。首先，在恢复一个被挂起的线程与该线程真 </p>
<p>正运行之间存在着严重的延迟。而且，非公平锁能更充分的利用 cpu 的时间片， </p>
<p>尽量的减少 cpu 空闲的状态时间。 </p>
<p>使用场景的话呢，其实还是和他们的属性一一相关，比如：如果业务中线程 </p>
<p>占用(处理)时间要远长于线程等待，那用非公平锁其实效率并不明显，但是用公 </p>
<p>平锁可以保证不会有线程被饿死。 </p>
<h5 id="请概述-AQS"><a href="#请概述-AQS" class="headerlink" title="请概述 AQS"></a>请概述 AQS</h5><p>是用来构建锁或者其他同步组件的基础框架，比如 ReentrantLock、 </p>
<p>ReentrantReadWriteLock 和 CountDownLatch 就是基于 AQS 实现的。它==使用了一== </p>
<p>==个 int  state成员变量表示同步状态，通过内置的 FIFO 队列来完成资源获取线程的排队== </p>
<p>==工作==。它是 CLH 队列锁的一种变体实现。它可以实现 2 种同步方式：独占式，共 </p>
<p>享式。</p>
<p>AQS 的主要使用方式是继承，子类通过继承 AQS 并实现它的抽象方法来管 </p>
<p>理同步状态，同步器的设计基于模板方法模式，所以如果要实现我们自己的同步 </p>
<p>工具类就需要覆盖其中几个可重写的方法，如 tryAcquire、tryReleaseShared 等等。 </p>
<p>这样设计的目的是同步组件（比如锁）是面向使用者的，它定义了使用者与 </p>
<p>同步组件交互的接口（比如可以允许两个线程并行访问），隐藏了实现细节；同 </p>
<p>步器面向的是锁的实现者，它简化了锁的实现方式，屏蔽了同步状态管理、线程 </p>
<p>的排队、等待与唤醒等底层操作。这样就很好地隔离了使用者和实现者所需关注 </p>
<p>的领域。</p>
<p>==在内部，AQS 维护一个共享资源 state，通过内置的 FIFO 来完成获取资源线== </p>
<p>==程的排队工作。该队列由一个一个的 Node 结点组成，每个 Node 结点维护一个== </p>
<p>==prev 引用和 next 引用，分别指向自己的前驱和后继结点，构成一个双端双向链== </p>
<p>==表。==</p>
<p>==同时与 Condition 相关的等待队列，节点类型也是 Node，构成一个单向链表==。 </p>
<h5 id="请概述-volatile"><a href="#请概述-volatile" class="headerlink" title="请概述 volatile"></a>请概述 volatile</h5><p>volatile 关键字的作用主要有两点： </p>
<p>多线程主要围绕可见性和原子性两个特性而展开，使用 volatile 关键字修饰 </p>
<p>的变量，保证了其在多线程之间的可见性，即每次读取到 volatile 变量，一定是 </p>
<p>最新的数据。但是 volatile 不能保证操作的原子，对任意单个 volatile 变量的读/ </p>
<p>写具有原子性，但类似于++这种复合操作不具有原子性。。 </p>
<p>代码底层在执行时为了获取更好的性能会对指令进行重排序，多线程下可能 </p>
<p>会出现一些意想不到的问题。使用 volatile 则会对禁止重排序，当然这也一定程 </p>
<p>度上降低了代码执行效率。 </p>
<p>同时在内存语义上，</p>
<p>==当写一个 volatile 变量时，JMM 会把该线程对应的本地== </p>
<p>==内存中的共享变量值刷新到主内存，==</p>
<p>==当读一个 volatile 变量时，JMM 会把该线程 对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。在 Java 中对于 volatile 修饰的变量，编译器在生成字节码时，会在指令序列== </p>
<p>==中插入内存屏障来禁止特定类型的处理器重排序问题、强制刷新和读取==。 </p>
<p>在具体实现上，volatile 关键字修饰的变量会存在一个“lock:”的前缀。它 </p>
<p>不是一种内存屏障，但是它能完成类似内存屏障的功能。Lock 会对 CPU 总线和 </p>
<p>高速缓存加锁，可以理解为 CPU 指令级的一种锁。 </p>
<p>同时该指令会将当前处理器缓存行的数据直接写会到系统内存中，且这个写回内 </p>
<p>存的操作会使在其他 CPU 里缓存了该地址的数据无效。</p>
<h5 id="缓存雪崩"><a href="#缓存雪崩" class="headerlink" title="缓存雪崩"></a>缓存雪崩</h5><p>我们可以简单的理解为：由于原有缓存失效，新缓存未到期间<br>(例如：我们设置缓存时采用了<strong>相同的过期时间</strong>，在同一时刻出现大面积的缓存过期)，所有原本应该访问缓存的请求都去查询数据库了，而对<strong>数据库CPU和内存造成巨大压力</strong>，严重的会造成数据库宕机。从而形成一系列连锁反应，造成整个系统崩溃。<br>缓存雪崩一般使用<strong>加锁</strong>（ 最多的解决方案）来保证不会有大量的线程对数据库一次性进行读写，从而避免失效时大量的并发请求落到底层存储系统上。还有一个简单方案就时讲缓存失效时间分散开。</p>
<p>和缓存击穿不同的是，    </p>
<p>​        <strong>缓存击穿指并发查同一条数据</strong>，缓存雪崩是不同数据都过期了，很多数据都查不到从而查数据库。</p>
<h5 id="缓存穿透"><a href="#缓存穿透" class="headerlink" title="缓存穿透"></a>缓存穿透</h5><p>   描述：</p>
<p>   缓存穿透是指<strong>缓存和数据库中都没有的数据</strong>，而用户不断发起请求，如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者，攻击会导致数据库压力过大。</p>
<p>  解决方案：</p>
<p>​    接口层增加校验，如用户鉴权校验，id做基础校验，id&lt;=0的直接拦截；<br>​    从缓存取不到的数据，在数据库中也没有取到，这时也可以将key-value对写为key-null，缓存有效时间可以设置短点，如30秒（设置太长会导致正常情况也没法使用）。这样可以防止攻击用户反复用同一个id暴力攻击</p>
<h5 id="缓存击穿"><a href="#缓存击穿" class="headerlink" title="缓存击穿"></a>缓存击穿</h5><p>  描述：</p>
<p>  缓存击穿是指<strong>缓存中没有但数据库中有的数据</strong>（一般是缓存时间到期），这时由于并发用户特别多，同时读缓存没读到数据，又同时去数据库去取数据，引起数据库压力瞬间增大，造成过大压力</p>
<p>解决方案：</p>
<ol>
<li>设置热点数据永远不过期。</li>
<li><strong>加互斥锁</strong>（只让一个线程去读取数据库更新缓存），互斥锁参考代码如下：</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title">getData</span><span class="params">(String key)</span> <span class="keyword">throws</span> InterruptedException</span>&#123;</span><br><span class="line">    <span class="comment">//从缓存读取数据</span></span><br><span class="line">    String result = getDataFromRedis(key);</span><br><span class="line">    <span class="comment">//缓存中不存在数据 </span></span><br><span class="line">    <span class="keyword">if</span> (result == <span class="keyword">null</span>)&#123;</span><br><span class="line">		<span class="comment">//去获取锁，获取成功，去数据库取数据 </span></span><br><span class="line">        <span class="keyword">if</span> (reenLock.tryLock())&#123;</span><br><span class="line">            <span class="comment">//从数据获取数据</span></span><br><span class="line">            result = getDataFromMysql(key);</span><br><span class="line">            <span class="comment">//更新缓存数据 </span></span><br><span class="line">            <span class="keyword">if</span> (result != <span class="keyword">null</span>)|&#123;</span><br><span class="line">                setDataToCache(key,result);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//释放锁</span></span><br><span class="line">            reenLock.unlock();</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;   <span class="comment">//获取锁失败</span></span><br><span class="line">            <span class="comment">//暂停100ms再重新去获取缓存数据 </span></span><br><span class="line">             Thread. sleep(<span class="number">100</span>); </span><br><span class="line">             result = getData(key);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	<span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>原文链接：<span class="exturl" data-url="aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2tvbmd0aWFvNS9hcnRpY2xlL2RldGFpbHMvODI3NzE2OTQ=" title="https://blog.csdn.net/kongtiao5/article/details/82771694">https://blog.csdn.net/kongtiao5/article/details/82771694<i class="fa fa-external-link"></i></span></p>
<h2 id="并发下的Map常见面试题汇总"><a href="#并发下的Map常见面试题汇总" class="headerlink" title="并发下的Map常见面试题汇总"></a>并发下的Map常见面试题汇总</h2><ol>
<li><p><strong>Q：HashMap 和 HashTable 有什么区别？</strong></p>
<ul>
<li>HashMap 是线程不安全的，HashTable 是线程安全的； </li>
<li>由于线程安全，所以 HashTable 的效率比不上 HashMap；</li>
<li>HashMap 最多只允许一条记录的键为 null，允许多条记录的值为 null， 而 HashTable 不允许；</li>
<li>HashMap 默认初始化数组的大小为 16，HashTable 为 11，前者扩容时， 扩大两倍，后者扩大两倍+1；</li>
<li>HashMap 需要重新计算 hash 值，而 HashTable 直接使用对象的 hashCode </li>
</ul>
</li>
<li><p><strong>Q：Java 中的另一个线程安全的与 HashMap极其类似的类是什么？同样是线程安全，它与HashTable在线程同步上有什么不同？</strong></p>
<ul>
<li>ConcurrentHashMap 类（是 Java 并发包 java.util.concurrent 中提供的一 个线程安全且高效的 HashMap 实现）。</li>
<li>HashTable 是使用 synchronize 关键字加锁的原理（就是对对象加锁）； </li>
<li>而针对 ConcurrentHashMap，在 JDK 1.7 中采用==分段锁==的方式；</li>
<li>JDK 1.8 中 直接采用了 ==CAS（无锁算法）+ synchronized==，也采用分段锁的方式并大大缩小了 锁的粒度。 </li>
</ul>
<p><strong>HashMap &amp; ConcurrentHashMap</strong> <strong>的区别？</strong> </p>
<p>A：除了加锁，原理上无太大区别。 </p>
<p>另外，HashMap 的键值对允许有 null，但是 ConCurrentHashMap 都不允许。 在数据结构上，红黑树相关的节点类 </p>
</li>
<li><p><strong>Q：为什么ConcurrentHashMap 比 HashTable效率要高？</strong> </p>
</li>
</ol>
<p>A：HashTable 使用一把锁==（锁住整个链表结构）==处理并发问题，多个线程 </p>
<p>竞争一把锁，容易阻塞； </p>
<p>ConcurrentHashMap :</p>
<ul>
<li>JDK 1.7 中使用分段锁（ReentrantLock + Segment + HashEntry），相当于把一 </li>
</ul>
<p>个 HashMap 分成多个段，每段分配一把锁，这样支持多线程访问。锁粒度：基 </p>
<p>于 Segment，包含多个 HashEntry。 </p>
<ul>
<li>JDK 1.8 中使用 CAS + synchronized + Node + 红黑树。锁粒度：Node（首结 </li>
</ul>
<p>点）（实现 Map.Entry&lt;K,V&gt;）。锁粒度降低了。 </p>
<ol start="4">
<li><strong>Q：针对 ConcurrentHashMap锁机制具体分析（JDK 1.7 VS JDK 1.8）？</strong> </li>
</ol>
<p>JDK 1.7 中，采用分段锁的机制，实现并发的更新操作，底层采用数组+链表 </p>
<p>的存储结构，包括两个核心静态内部类 Segment 和 HashEntry。 </p>
<p>①、Segment 继承 ReentrantLock（重入锁） 用来充当锁的角色，每个 </p>
<p>Segment 对象守护每个散列映射表的若干个桶； </p>
<p>②、HashEntry 用来封装映射表的键-值对； </p>
<p>③、每个桶是由若干个 HashEntry 对象链接起来的链表。 </p>
<p>JDK 1.8 中，采用 Node + CAS + Synchronized 来保证并发安全。取消类 </p>
<p>Segment，直接用 table 数组存储键值对；当 HashEntry 对象组成的链表长度超 </p>
<p>过 TREEIFY_THRESHOLD 时，链表转换为红黑树，提升性能。底层变更为数组 + </p>
<p>链表 + 红黑树。 </p>
<ol start="5">
<li><strong>Q：ConcurrentHashMap在JDK 1.8 中，为什么要使用内置锁 synchronized 来代替重入ReentrantLock？</strong> </li>
</ol>
<p>A：</p>
<p>1、JVM 开发团队在 1.8 中对 synchronized 做了大量性能上的优化，而且基 </p>
<p>于 JVM 的 synchronized 优化空间更大，更加自然。</p>
<p>2、在大量的数据操作下，对于 JVM 的内存压力，基于 API 的 </p>
<p>ReentrantLock 会开销更多的内存。 </p>
<ol start="6">
<li><strong>Q：ConcurrentHashMap 简单介绍？</strong> </li>
</ol>
<blockquote>
<p>v1.7 中采用segment数组存储结构，分段锁技术，实现ReentrantLock接口，默认并发度16（不可扩容），默认容量16，初始每个segment中table大小为1，get获取数据时不加锁使用volatile关键词保证可见性；扩容时table容量按2的指数级扩容</p>
<p>v1.8 中采用Node数组存储结构，每个链表长达大于8时链表转换成红黑树（链表查找时间复杂度o(n)，红黑树时间复杂度O(logn)）</p>
</blockquote>
<p>①、重要的常量： </p>
<p>private transient volatile int sizeCtl; </p>
<p>当为负数时，-1 表示正在初始化，-N 表示 N - 1 个线程正在进行扩容； </p>
<p>当为 0 时，表示 table 还没有初始化； </p>
<p>当为其他正数时，表示初始化或者下一次进行扩容的大小。 </p>
<p>②、数据结构： </p>
<p>Node 是存储结构的基本单元，继承 HashMap 中的 Entry，用于存储数据； </p>
<p>TreeNode 继承 Node，但是数据结构换成了二叉树结构，是红黑树的存储 </p>
<p>结构，用于红黑树中存储数据； </p>
<p>TreeBin 是封装 TreeNode 的容器，提供转换红黑树的一些条件和锁的控制。 </p>
<p>③、存储对象时（put() 方法）： </p>
<ul>
<li><p>如果没有初始化，就调用 initTable() 方法来进行初始化； </p>
</li>
<li><p>如果没有 hash 冲突就直接 CAS 无锁插入； </p>
</li>
<li><p>如果需要扩容，就先进行扩容； </p>
</li>
<li><p>如果存在 hash 冲突，就加锁来保证线程安全，两种情况：一种是链表形 式就直接遍历到尾端插入，一种是红黑树就按照红黑树结构插入； </p>
</li>
<li><p>如果该链表的数量大于阀值 8，就要先转换成红黑树的结构，break 再一 次进入循环 </p>
</li>
<li><p>如果添加成功就调用 addCount() 方法统计 size，并且检查是否需要扩容。 </p>
</li>
</ul>
<p>④、扩容方法 transfer()：默认容量为 16，扩容时，容量变为原来的两倍。 </p>
<p>helpTransfer()：调用多个工作线程一起帮助进行扩容，这样的效率就会更高。 </p>
<p>⑤、获取对象时（get()方法）： </p>
<ul>
<li><p>计算 hash 值，定位到该 table 索引位置，如果是首结点符合就返回； </p>
</li>
<li><p>如果遇到扩容时，会调用标记正在扩容结点 ForwardingNode.find()方法， </p>
</li>
</ul>
<p>查找该结点，匹配就返回； </p>
<ul>
<li>以上都不符合的话，就往下遍历结点，匹配就返回，否则最后就返回 null。 </li>
</ul>
<ol start="7">
<li><strong>Q：ConcurrentHashMap 的并发度是什么？</strong> </li>
</ol>
<p>A：1.7 中程序运行时能够同时更新 ConccurentHashMap 且不产生锁竞争的 </p>
<p>最大线程数。默认为 16，且可以在构造函数中设置。当用户设置并发度时， </p>
<p>ConcurrentHashMap 会使用大于等于该值的最小 2 幂指数作为实际并发度（假如 </p>
<p>用户设置并发度为 17，实际并发度则为 32）。</p>
<h1 id="分布式缓存与一致性哈希"><a href="#分布式缓存与一致性哈希" class="headerlink" title="分布式缓存与一致性哈希"></a><strong>分布式缓存与一致性哈希</strong></h1><p>以集群的方式提供缓存服务，有两种实现； </p>
<ol>
<li>需要更新同步的分布式缓存，所有的服务器保存相同的缓存数据，带来的问题就是，缓存的数据量受限制，其次，数据要在所有的机器上同步，代价 </li>
</ol>
<p>很大。 </p>
<ol start="2">
<li>每台机器只缓存一部分数据，然后通过一定的算法选择缓存服务器。常见的余数 hash 算法存在当有服务器上下线的时候，大量缓存数据重建的问题。 </li>
</ol>
<p>所以提出了一致性哈希算法。 </p>
<p><strong>一致性哈希</strong>： </p>
<ol>
<li><p>首先求出服务器（节点）的哈希值，并将其配置到 0～2 的 32 次方的圆（continuum）上。 </p>
</li>
<li><p>然后采用同样的方法求出存储数据的键的哈希值，并映射到相同的圆上。 </p>
</li>
<li><p>然后从数据映射到的位置开始顺时针查找，将数据保存到找到的第一个服务器上。如果超过 2^32^ 仍然找不到服务器，就会保存到第一台服务器上。一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据，具有较好的容错性和可扩展性。 </p>
</li>
</ol>
<p><strong>数据倾斜</strong>： </p>
<p>一致性哈希算法在==服务节点太少时==，容易因为节点分部不均匀而造成数据倾斜问题，此时必然造成大量数据集中到 Node A 上，而只有极少量会定位到 Node B 上。</p>
<p>为了解决这种数据倾斜问题，一致性哈希算法引入了虚拟节点机制，即对每一个服务节点计算多个哈希，每个计算结果位置都放置一个此服务节点， 称为==虚拟节点==。</p>
<p>具体做法可以在服务器 ip 或主机名的后面增加编号来实现。例如，可以为每台服务器计算三个虚拟节点，于是可以分别计算 “Node A#1”、 “Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“Node B#3”的哈希值，于是形成六个虚拟节点：同时数据定位算法不变，只是多了一步虚拟节点到 实际节点的映射，例如定位到“NodeA#1”、“Node A#2”、“Node A#3”三个虚拟节点的数据均定位到 Node A 上。</p>
<p>这样就解决了服务节点少时数据倾斜的问 题。在实际应用中，<strong>通常将虚拟节点数设置为 32 甚至更大</strong>，因此即使很少的服务节点也能做到相对均匀的数据分布。</p>

    </div>

    


<div>
  
    <div>
    
	<br /> <br /> <br />
	<div style="text-align:center;color: #678;font-size:18px;">======================</div>
        <div style="text-align:center;color: #678;font-size:18px;">全 文 结 束&ensp;&ensp;<i class="fa fa-leanpub"></i>&ensp;&ensp;感 谢 阅 读</div>
	<div style="text-align:center;color: #678;font-size:18px;">======================</div>
    
</div>
  
</div>

    
    
    
        <div class="reward-container">
  <div>坚持原创技术分享，您的支持将鼓励我继续创作！</div>
  <button disable="enable" onclick="var qr = document.getElementById(&quot;qr&quot;); qr.style.display = (qr.style.display === 'none') ? 'block' : 'none';">
    打赏
  </button>
  <div id="qr" style="display: none;">
      
      <div style="display: inline-block;">
        <img src="/images/wechatpay.png" alt="Haifeng Cao 微信支付">
        <p>微信支付</p>
      </div>
      
      <div style="display: inline-block;">
        <img src="/images/alipay.jpg" alt="Haifeng Cao 支付宝">
        <p>支付宝</p>
      </div>

  </div>
</div>

        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>Haifeng Cao
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="https://www.caohaifeng.site/2019/12/11/Java%E6%AF%8F%E6%97%A5%E4%B8%80%E9%A2%98/" title="java每日一题">https://www.caohaifeng.site/2019/12/11/Java%E6%AF%8F%E6%97%A5%E4%B8%80%E9%A2%98/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <span class="exturl" data-url="aHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLXNhLzQuMC9udWxs"><i class="fa fa-fw fa-creative-commons"></i>BY-NC-SA</span> 许可协议。转载请注明出处！
  </li>
</ul>
</div>


      <footer class="post-footer">

        

          <div class="post-nav">
            <div class="post-nav-next post-nav-item">
                <a href="/2019/12/11/centos7%E5%AE%89%E8%A3%85jenkins/" rel="next" title="centos7安装jenkins">
                  <i class="fa fa-chevron-left"></i> centos7安装jenkins
                </a>
            </div>

            <span class="post-nav-divider"></span>

            <div class="post-nav-prev post-nav-item">
                <a href="/2019/12/11/velocity/" rel="prev" title="velocity">
                  velocity <i class="fa fa-chevron-right"></i>
                </a>
            </div>
          </div>
      </footer>
    
  </article>
  
  
  

  </div>


          </div>
          
      <div class="tabs tabs-comment">
        <ul class="nav-tabs">
            <li class="tab"><a href="#comment-gitalk">gitalk</a></li>
            <li class="tab"><a href="#comment-valine">valine</a></li>
        </ul>
        <div class="tab-content">
            <div class="tab-pane gitalk" id="comment-gitalk">
              <div class="comments" id="gitalk-container"></div>
            </div>
            <div class="tab-pane valine" id="comment-valine">
              <div class="comments" id="comments"></div>
            </div>
        </div>
      </div>
      <script>
        window.addEventListener('tabs:register', () => {
          let activeClass = 'gitalk';
          if (activeClass) {
            let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
            if (activeTab) {
              activeTab.click();
            }
          }
        });
      </script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#Java每日一题"><span class="nav-number">1.</span> <span class="nav-text">Java每日一题</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#每日一题：什么是缓存穿透？如何解决？"><span class="nav-number">1.0.0.0.1.</span> <span class="nav-text">每日一题：什么是缓存穿透？如何解决？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#每日一小题，迈进BATJ-今天的题目是spring框架模块"><span class="nav-number">1.0.0.0.2.</span> <span class="nav-text">每日一小题，迈进BATJ:今天的题目是spring框架模块</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#每日一题：Redis单线程为什么这么快？"><span class="nav-number">1.0.0.0.3.</span> <span class="nav-text">每日一题：Redis单线程为什么这么快？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#每日一题：SpringCloud断路器的作用"><span class="nav-number">1.0.0.0.4.</span> <span class="nav-text">每日一题：SpringCloud断路器的作用</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#每日一题：为什么要有TIME-WAIT状态？"><span class="nav-number">1.0.0.0.5.</span> <span class="nav-text">每日一题：为什么要有TIME_WAIT状态？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#在-java-中守护线程和用户线程的区别？"><span class="nav-number">1.0.0.0.6.</span> <span class="nav-text">在 java 中守护线程和用户线程的区别？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#线程与进程的区别"><span class="nav-number">1.0.0.0.7.</span> <span class="nav-text">线程与进程的区别</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#什么是多线程中的上下文切换"><span class="nav-number">1.0.0.0.8.</span> <span class="nav-text">什么是多线程中的上下文切换</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#死锁与活锁的区别，死锁与饥饿的区别？"><span class="nav-number">1.0.0.0.9.</span> <span class="nav-text">死锁与活锁的区别，死锁与饥饿的区别？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#synchronized-底层实现原理"><span class="nav-number">1.0.0.0.10.</span> <span class="nav-text">synchronized 底层实现原理</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#什么是线程组，为什么在-Java-中不推荐使用？"><span class="nav-number">1.0.0.0.11.</span> <span class="nav-text">什么是线程组，为什么在 Java 中不推荐使用？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#什么是-Executor-框架？为什么使用-Executor-框架？"><span class="nav-number">1.0.0.0.12.</span> <span class="nav-text">什么是 Executor 框架？为什么使用 Executor 框架？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#在-Java-中-Executor-和-Executors-的区别？"><span class="nav-number">1.0.0.0.13.</span> <span class="nav-text">在 Java 中 Executor 和 Executors 的区别？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#什么是原子操作？在-Java-Concurrency-API-中有哪些原子类-atomicclasses-？"><span class="nav-number">1.0.0.0.14.</span> <span class="nav-text">什么是原子操作？在 Java Concurrency API 中有哪些原子类(atomicclasses)？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#Java-Concurrency-API-中的-Lock-接口-Lock-interface-是什么？对比synchronized-它有什么优势？"><span class="nav-number">1.0.0.0.15.</span> <span class="nav-text">Java Concurrency API 中的 Lock 接口(Lock interface)是什么？对比synchronized 它有什么优势？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#什么是阻塞队列？阻塞队列的实现原理是什么？如何使用阻塞队列来实现生产者-消费者模型？"><span class="nav-number">1.0.0.0.16.</span> <span class="nav-text">什么是阻塞队列？阻塞队列的实现原理是什么？如何使用阻塞队列来实现生产者-消费者模型？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#什么是-Callable-和-Future"><span class="nav-number">1.0.0.0.17.</span> <span class="nav-text">什么是 Callable 和 Future?</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#什么是-FutureTask"><span class="nav-number">1.0.0.0.18.</span> <span class="nav-text">什么是 FutureTask?</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#什么是并发容器的实现？"><span class="nav-number">1.0.0.0.19.</span> <span class="nav-text">什么是并发容器的实现？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#多线程同步和互斥有几种实现方法，都是什么？"><span class="nav-number">1.0.0.0.20.</span> <span class="nav-text">多线程同步和互斥有几种实现方法，都是什么？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#为什么我们调用-start-方法时会执行-run-方法，为什么我们不能直接调用-run-方法"><span class="nav-number">1.0.0.0.21.</span> <span class="nav-text">为什么我们调用 start()方法时会执行 run()方法，为什么我们不能直接调用 run()方法?</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#在-Java-中-CycliBarriar-和-CountdownLatch-有什么区别？"><span class="nav-number">1.0.0.0.22.</span> <span class="nav-text">在 Java 中 CycliBarriar 和 CountdownLatch 有什么区别？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#什么是不可变对象，它对写并发应用有什么帮助？"><span class="nav-number">1.0.0.0.23.</span> <span class="nav-text">什么是不可变对象，它对写并发应用有什么帮助？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#notify-和-notifyAll-有什么区别？"><span class="nav-number">1.0.0.0.24.</span> <span class="nav-text">notify()和 notifyAll()有什么区别？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#什么是可重入锁（ReentrantLock）？谈谈它的实现。"><span class="nav-number">1.0.0.0.25.</span> <span class="nav-text">什么是可重入锁（ReentrantLock）？谈谈它的实现。</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#当一个线程进入某个对象的一个-synchronized-的实例方法后，其它线程是否可进入此对象的其它方法？"><span class="nav-number">1.0.0.0.26.</span> <span class="nav-text">当一个线程进入某个对象的一个 synchronized 的实例方法后，其它线程是否可进入此对象的其它方法？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#乐观锁和悲观锁的理解及如何实现，有哪些实现方式？"><span class="nav-number">1.0.0.0.27.</span> <span class="nav-text">乐观锁和悲观锁的理解及如何实现，有哪些实现方式？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#什么是-CAS-操作，缺点是什么？"><span class="nav-number">1.0.0.0.28.</span> <span class="nav-text">什么是 CAS 操作，缺点是什么？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#SynchronizedMap-和-ConcurrentHashMap-有什么区别？"><span class="nav-number">1.0.0.0.29.</span> <span class="nav-text">SynchronizedMap 和 ConcurrentHashMap 有什么区别？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#写时复制容器可以用于什么应用场景？"><span class="nav-number">1.0.0.0.30.</span> <span class="nav-text">写时复制容器可以用于什么应用场景？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#volatile-有什么用？能否用一句话说明下-volatile-的应用场景？"><span class="nav-number">1.0.0.0.31.</span> <span class="nav-text">volatile 有什么用？能否用一句话说明下 volatile 的应用场景？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#在-java-中-wait-和-sleep-方法的不同？"><span class="nav-number">1.0.0.0.32.</span> <span class="nav-text">在 java 中 wait 和 sleep 方法的不同？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#一个线程运行时发生异常会怎样？"><span class="nav-number">1.0.0.0.33.</span> <span class="nav-text">一个线程运行时发生异常会怎样？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#什么是-ThreadLocal-变量？"><span class="nav-number">1.0.0.0.34.</span> <span class="nav-text">什么是 ThreadLocal 变量？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#Java-中-interrupted-和-isInterrupted-方法的区别？"><span class="nav-number">1.0.0.0.35.</span> <span class="nav-text">Java 中 interrupted 和 isInterrupted 方法的区别？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#为什么-wait-和-notify-方法要在同步块中调用？"><span class="nav-number">1.0.0.0.36.</span> <span class="nav-text">为什么 wait 和 notify 方法要在同步块中调用？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#为什么你应该在循环中检查等待条件"><span class="nav-number">1.0.0.0.37.</span> <span class="nav-text">为什么你应该在循环中检查等待条件?</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#怎么检测一个线程是否拥有锁？"><span class="nav-number">1.0.0.0.38.</span> <span class="nav-text">怎么检测一个线程是否拥有锁？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#你如何在-Java-中获取线程堆栈？"><span class="nav-number">1.0.0.0.39.</span> <span class="nav-text">你如何在 Java 中获取线程堆栈？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#Java-线程池中-submit-和-execute-方法有什么区别？"><span class="nav-number">1.0.0.0.40.</span> <span class="nav-text">Java 线程池中 submit() 和 execute()方法有什么区别？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#你对线程优先级的理解是什么？"><span class="nav-number">1.0.0.0.41.</span> <span class="nav-text">你对线程优先级的理解是什么？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#你如何确保-main-方法所在的线程是-Java-程序最后结束的线程"><span class="nav-number">1.0.0.0.42.</span> <span class="nav-text">你如何确保 main()方法所在的线程是 Java 程序最后结束的线程</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#为什么-Thread-类的-sleep-和-yield-方法是静态的？"><span class="nav-number">1.0.0.0.43.</span> <span class="nav-text">为什么 Thread 类的 sleep()和 yield ()方法是静态的？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#现在有-T1、T2、T3-三个线程，你怎样保证-T2-在-T1-执行完后执行，T3-在-T2-执行完后执行？"><span class="nav-number">1.0.0.0.44.</span> <span class="nav-text">现在有 T1、T2、T3 三个线程，你怎样保证 T2 在 T1 执行完后执行，T3 在 T2 执行完后执行？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#你需要实现一个高效的缓存，它允许多个用户读，但只允许一个用户写，以此来保持它的完整性，你会怎样去实现它？"><span class="nav-number">1.0.0.0.45.</span> <span class="nav-text">你需要实现一个高效的缓存，它允许多个用户读，但只允许一个用户写，以此来保持它的完整性，你会怎样去实现它？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#用-Java-编程一个会导致死锁的程序，你将怎么解决？"><span class="nav-number">1.0.0.0.46.</span> <span class="nav-text">用 Java 编程一个会导致死锁的程序，你将怎么解决？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#Java-中如何停止一个线程？"><span class="nav-number">1.0.0.0.47.</span> <span class="nav-text">Java 中如何停止一个线程？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#JVM-中哪个参数是用来控制线程的栈堆栈大小的"><span class="nav-number">1.0.0.0.48.</span> <span class="nav-text">JVM 中哪个参数是用来控制线程的栈堆栈大小的</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#如果同步块内的线程抛出异常锁会释放吗？"><span class="nav-number">1.0.0.0.49.</span> <span class="nav-text">如果同步块内的线程抛出异常锁会释放吗？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#单例模式的双重检查实现是什么？为什么并不安全？如何在-Java-中创建线程安全的-Singleton？"><span class="nav-number">1.0.0.0.50.</span> <span class="nav-text">单例模式的双重检查实现是什么？为什么并不安全？如何在 Java 中创建线程安全的 Singleton？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#写出-3-条你遵循的多线程最佳实践"><span class="nav-number">1.0.0.0.51.</span> <span class="nav-text">写出 3 条你遵循的多线程最佳实践</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#请概述线程池的创建参数，怎么样合理配置一个线程池的参数？"><span class="nav-number">1.0.0.0.52.</span> <span class="nav-text">请概述线程池的创建参数，怎么样合理配置一个线程池的参数？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#请概述锁的公平和非公平，JDK-内部是如何实现的。"><span class="nav-number">1.0.0.0.53.</span> <span class="nav-text">请概述锁的公平和非公平，JDK 内部是如何实现的。</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#请概述-AQS"><span class="nav-number">1.0.0.0.54.</span> <span class="nav-text">请概述 AQS</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#请概述-volatile"><span class="nav-number">1.0.0.0.55.</span> <span class="nav-text">请概述 volatile</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#缓存雪崩"><span class="nav-number">1.0.0.0.56.</span> <span class="nav-text">缓存雪崩</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#缓存穿透"><span class="nav-number">1.0.0.0.57.</span> <span class="nav-text">缓存穿透</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#缓存击穿"><span class="nav-number">1.0.0.0.58.</span> <span class="nav-text">缓存击穿</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#并发下的Map常见面试题汇总"><span class="nav-number">1.1.</span> <span class="nav-text">并发下的Map常见面试题汇总</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#分布式缓存与一致性哈希"><span class="nav-number">2.</span> <span class="nav-text">分布式缓存与一致性哈希</span></a></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="Haifeng Cao"
      src="/images/avatar.jpg">
  <p class="site-author-name" itemprop="name">Haifeng Cao</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">5</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">2</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">3</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="feed-link motion-element">
    <a href="/atom.xml" rel="alternate">
      <i class="fa fa-rss"></i>RSS
    </a>
  </div>
  <div class="chat motion-element"><i class="fa fa-comment"></i>
    Chat
  </a>
  </div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2hldm9sZg==" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;hevolf"><i class="fa fa-fw fa-github"></i>GitHub</span>
      </span>
      <span class="links-of-author-item">
        <span class="exturl" data-url="bWFpbHRvOmNhb2hhaWZlbmd4QDE2My5jb20=" title="E-Mail → mailto:caohaifengx@163.com"><i class="fa fa-fw fa-envelope"></i>E-Mail</span>
      </span>
      <span class="links-of-author-item">
        <span class="exturl" data-url="aHR0cHM6Ly93ZWliby5jb20veW91cm5hbWU=" title="微博 → https:&#x2F;&#x2F;weibo.com&#x2F;yourname"><i class="fa fa-fw fa-weibo"></i>微博</span>
      </span>
  </div>


  <div class="links-of-blogroll motion-element">
    <div class="links-of-blogroll-title">
      <i class="fa fa-fw fa-link"></i>
      友情链接
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2hldm9sZg==" title="https:&#x2F;&#x2F;github.com&#x2F;hevolf">GitHub</span>
        </li>
        <li class="links-of-blogroll-item">
          <span class="exturl" data-url="aHR0cHM6Ly93d3cuYmFpZHUuY29t" title="https:&#x2F;&#x2F;www.baidu.com">百度</span>
        </li>
    </ul>
  </div>
<!-- CloudCalendar -->
<div class="widget-wrap" style="width: 90%;margin-left: auto;margin-right: auto; opacity: 0.97;">
	<div class="widget" id="CloudCalendar"></div>
</div>
      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2019</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Haifeng Cao</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-area-chart"></i>
    </span>
    <span title="站点总字数">55k</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
    <span title="站点阅读时长">50 分钟</span>
</div>
  <div class="addthis_inline_share_toolbox">
    <script src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-5dd7eec81a2121ca" async="async"></script>
  </div>

        






  <script>
  function leancloudSelector(url) {
    return document.getElementById(url).querySelector('.leancloud-visitors-count');
  }
  if (CONFIG.page.isPost) {
    function addCount(Counter) {
      var visitors = document.querySelector('.leancloud_visitors');
      var url = visitors.getAttribute('id').trim();
      var title = visitors.getAttribute('data-flag-title').trim();

      Counter('get', `/classes/Counter?where=${JSON.stringify({ url })}`)
        .then(response => response.json())
        .then(({ results }) => {
          if (results.length > 0) {
            var counter = results[0];
              leancloudSelector(url).innerText = counter.time + 1;
            Counter('put', '/classes/Counter/' + counter.objectId, { time: { '__op': 'Increment', 'amount': 1 } })
              .then(response => response.json())
              .catch(error => {
                console.log('Failed to save visitor count', error);
              })
          } else {
              Counter('post', '/classes/Counter', { title: title, url: url, time: 1 })
                .then(response => response.json())
                .then(() => {
                  leancloudSelector(url).innerText = 1;
                })
                .catch(error => {
                  console.log('Failed to create', error);
                });
          }
        })
        .catch(error => {
          console.log('LeanCloud Counter Error', error);
        });
    }
  } else {
    function showTime(Counter) {
      var visitors = document.querySelectorAll('.leancloud_visitors');
      var entries = [...visitors].map(element => {
        return element.getAttribute('id').trim();
      });

      Counter('get', `/classes/Counter?where=${JSON.stringify({ url: { '$in': entries } })}`)
        .then(response => response.json())
        .then(({ results }) => {
          if (results.length === 0) {
            document.querySelectorAll('.leancloud_visitors .leancloud-visitors-count').forEach(element => {
              element.innerText = 0;
            });
            return;
          }
          for (var i = 0; i < results.length; i++) {
            var item = results[i];
            var url = item.url;
            var time = item.time;
            leancloudSelector(url).innerText = time;
          }
          for (var i = 0; i < entries.length; i++) {
            var url = entries[i];
            var element = leancloudSelector(url);
            if (element.innerText == '') {
              element.innerText = 0;
            }
          }
        })
        .catch(error => {
          console.log('LeanCloud Counter Error', error);
        });
    }
  }

  fetch('https://app-router.leancloud.cn/2/route?appId=932Lws0WCoOBR1QH1YcClNyO-gzGzoHsz')
    .then(response => response.json())
    .then(({ api_server }) => {
      var Counter = (method, url, data) => {
        return fetch(`https://${api_server}/1.1${url}`, {
          method: method,
          headers: {
            'X-LC-Id': '932Lws0WCoOBR1QH1YcClNyO-gzGzoHsz',
            'X-LC-Key': 'qhb4dhObEw9qngzRpoxXrtEw',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data)
        });
      };
      if (CONFIG.page.isPost) {
        const localhost = /http:\/\/(localhost|127.0.0.1|0.0.0.0)/;
        if (localhost.test(document.URL)) return;
        addCount(Counter);
      } else if (document.querySelectorAll('.post-title-link').length >= 1) {
        showTime(Counter);
      }
    });
  </script>






        
      </div>
    </footer>
  </div>

  
  
  <script color='0,0,255' opacity='0.5' zIndex='-1' count='99' src="/lib/canvas-nest/canvas-nest.min.js"></script>
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>
<script src="/js/utils.js"></script><script src="/js/motion.js"></script>
<script src="/js/schemes/pisces.js"></script>
<script src="/js/next-boot.js"></script>



  
  <script>
    (function(){
      var bp = document.createElement('script');
      var curProtocol = window.location.protocol.split(':')[0];
      bp.src = (curProtocol === 'https') ? 'https://zz.bdstatic.com/linksubmit/push.js' : 'http://push.zhanzhang.baidu.com/push.js';
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(bp, s);
    })();
  </script>
















  

  

<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.css">

<script>
  NexT.utils.getScript('//cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js', () => {
    var gitalk = new Gitalk({
      clientID: '0672eb3ee58faee4935d',
      clientSecret: '2de10f83bc44b7d86db607b2a3db41d6b845d59f',
      repo: 'itheone_gitalk',
      owner: 'hevolf',
      admin: ['hevolf'],
      id: 'ceb3f5b2d4457305ea90a99e0a5c797c',
        language: 'zh-CN',
      distractionFreeMode: 'true'
    });
    gitalk.render('gitalk-container');
  }, window.Gitalk);
</script>
<!-- calendar widget -->

    <script src="//cdn.jsdelivr.net/gh/theme-next/theme-next-calendar/calendar.min.js"></script>
    <script src="//cdn.jsdelivr.net/gh/theme-next/theme-next-calendar/languages.min.js"></script>
    <script>
    $(function() {
        $('#CloudCalendar').aCalendar('zh-CN',
            $.extend(
                '', {
                    single:true,
                    root:'/calendar/'
                }
            )
        );
    });
    </script>



<script>
NexT.utils.getScript('//unpkg.com/valine/dist/Valine.min.js', () => {
  var GUEST = ['nick', 'mail', 'link'];
  var guest = 'nick,mail';
  guest = guest.split(',').filter(item => {
    return GUEST.includes(item);
  });
  new Valine({
    el: '#comments',
    verify: false,
    notify: false,
    appId: '932Lws0WCoOBR1QH1YcClNyO-gzGzoHsz',
    appKey: 'qhb4dhObEw9qngzRpoxXrtEw',
    placeholder: "Just go go",
    avatar: 'mm',
    meta: guest,
    pageSize: '10' || 10,
    visitor: false,
    lang: '' || 'zh-cn',
    path: location.pathname,
    recordIP: false,
    serverURLs: ''
  });
}, window.Valine);
</script>

</body>
</html>